背景介绍
Define Layer(定义网络层):是深度学习中的基础内容,想使用深度学习方法解决实际问题,首先就需要建立一个网络层,今天以LeNet-5模型为例,给入门的小伙伴们提供TensorFlow2.0两种定义网络层的方法。
第一种方法
只用TensorFlow中定义好的网络层,直接使用keras.layer下的网络层类即可,是最简单的网络层创建方法,缺点也很明显,灵活度很低。
1 | import tensorflow.keras as keras |
第二种方法
通过继承keras.layer.Layer来创建模型,是最灵活的方式,可以满足任何网络层的定义,但是难度也更大,必须通过重载call函数自定义调用方式。
__init__函数,是自定义层的构造函数,可以在这里准备一些和输入尺寸无关的网络层,如定义一些参数,接收构造函数的输入等等。
call函数,inputs是上一层网络的输出,return是自定义网络的输出,在call函数中写入本层要实现的内容。
build函数,上面两个都是必须的函数,而build函数是根据需要来创建的,一些参数可能需要根据上一层的网络的输出来确定的,如reshape,resize等等操作,因此这些参数的定义无法在__init__中完成,所以需要在build中完成参数的定义,input_shape参数是上一层网络的输出维度。在没有定义build函数时,会默认调用一次空的build函数。
dynamic=False参数,在调用父类的构造函数时,可以传入dynamic参数,其中默认为False,搭建静态图,如果需要动态调整参数,则需要写入dynamic=True
因此当我们需要自定义一个网络层时,我们的思路为:
- 根据需要判断自定义层是否可以由keras.layer提供的网络层组合而成,如CNN中大量存在Convlution+BN+ReLU层,因此我们可以定义一个层一次性完成三个步骤,而且这三个层都存在于keras.layer中,所以使用卷积层时也不必要使用build函数,直接调用keras.layers.Conv2D接口即可。
1
2
3
4
5
6
7
8
9
10
11
12
13class Conv_Bn_ReLU(keras.layers.Layer):
def __init__(self, filters, kernel_size, strides, padding, name):
super(Conv_Bn_ReLU, self).__init__(name=name)
self.conv = keras.layers.Conv2D(filters, kernel_size, strides, padding)
self.bn = keras.layers.BatchNormalization()
self.relu = keras.layers.ReLU()
def call(self, inputs, **kwargs):
conv = self.conv(inputs)
bn = self.bn(conv)
output = self.relu(bn)
return output - 根据需要判断是否必须通过上一层输出的尺寸进行操作,如果是则需要定义build函数,如果不需要根据上一层尺寸来判断,则可以在__init__中创建。
定义参数说明:
- 在__init__中定义参数,可以使用self.add_weight()创建指定形状的参数,但是无法创建和输入尺寸相关的参数,**也可以使用tf.Variable()创建指定形状的参数,其中括号里可以为numpy数组,也可以为EagerTensor(动态张量)**。
- 在build中定义参数,可以使用self.add_weight()创建指定形状的参数,而且可以创建和输入尺寸相关的参数,也可以使用tf.Variable()创建指定形状的参数,但是使用Input层,build方法或者使用fit和train_on_batch训练时会传入输入参数尺寸,因为没有具体数值,因此会自动启动静态图,在静态模式下无法产生EagerTensor(动态张量),所以不能在Variable的参数列表中传入动态张量,但是仍然可以传入numpy格式的参数。。
- 因此推荐在__init__中搭建和输入不相关的参数,在build中搭建和输入相关的参数。
下面是完全使用自定义网络层完成的LeNet-5网络模型。
1 | import tensorflow as tf |
小结
网络层的第二种定义方式和模型定义的第三种定义方式非常类似,在call函数中定义符合自己需要的网络层,一般的顺序是先从keras.layer中寻找自己需要的层是否已经提供,如卷积层,池化层,全连接层等等,这时不需要我们手动定义,但是如果某些层非常复杂,如SE注意力层,需要我们手动定义,希望小伙伴们可以多多练习。